#region License
/* Copyright (c) 2011 Maksymilian Mulawa
	
Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
   3. The name of the author may not be used to endorse or promote products 
 * derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using log4net;
using ReplicationExplorer.DomainModel.Distributor.Entities;
using ReplicationExplorer.DomainModel.Distributor.Repositories;
using ReplicationExplorer.DomainModel.Infrastructure;
using ReplicationExplorer.DomainModel.SqlServerAgent;

namespace ReplicationExplorer.Repositories
{
    public class DistributorRepository : IDistributorRepository
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(DistributorRepository));

        private readonly IDistributorSession _distributorSession;

        public DistributorRepository(IDistributorSession distributorSession)
        {
            _distributorSession = distributorSession;
        }

        public DistributorServer GetDistributor()
        {
            DistributorServer distributorServer = new DistributorServer();
            try
            {
                using (SqlConnection connection = new SqlConnection(_distributorSession.DistributorConnectionString))
                {
                    connection.Open();

                    distributorServer.ServerVersion = new SqlServerVersion(connection.ServerVersion);
                    SqlCommand getDistributorCmd = new SqlCommand(ReplicationExplorerSqlQueries.sp_get_distributor, connection);
                    getDistributorCmd.CommandTimeout = _distributorSession.SqlQueryTimeoutInSeconds;
                    using (SqlDataReader distributorReader = getDistributorCmd.ExecuteReader())
                    {
                        if (distributorReader.Read())
                        {
                            distributorServer.IsDistributorInstalled = (bool)distributorReader["installed"];
                            distributorServer.Server = Convert.IsDBNull(distributorReader["distribution server"])
                                                           ? string.Empty
                                                           : (string)distributorReader["distribution server"];
                            distributorServer.IsDistributionDatabaseInstalled =
                                (bool)distributorReader["distribution db installed"];
                            distributorServer.IsPublisher = (bool)distributorReader["is distribution publisher"];
                            distributorServer.HasRemotePublisher = (bool)distributorReader["has remote distribution publisher"];
                        }
                    }

                    if (distributorServer.IsDistributorLocallyInstalled)
                    {
                        distributorServer.DistributionDatabases = GetDistributionDatabases(connection);
                    }
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
                throw;
            }

            return distributorServer;
        }

        public List<DistributionDatabase> GetDistributionDatabases()
        {
            List<DistributionDatabase> distributionDatabases;
            using (SqlConnection connection = new SqlConnection(_distributorSession.DistributorConnectionString))
            {
                connection.Open();
                distributionDatabases = GetDistributionDatabases(connection);
            }

            return distributionDatabases;
        }

        private List<DistributionDatabase> GetDistributionDatabases(SqlConnection connection)
        {
            List<DistributionDatabase> distributionDatabases = new List<DistributionDatabase>();
            GetDistributionDatabases(connection, distributionDatabases);
            if (distributionDatabases.Count > 0)
            {
                GetDistributionDatabasesExtendedMetadata(connection, distributionDatabases);
            }
            return distributionDatabases;
        }

        private void GetDistributionDatabasesExtendedMetadata(SqlConnection connection, List<DistributionDatabase> distributionDatabases)
        {
            try
            {
                SqlCommand distributionDBExtendedCmd = new SqlCommand(ReplicationExplorerSqlQueries.sp_helpdistributiondb, connection);
                distributionDBExtendedCmd.CommandType = CommandType.StoredProcedure;
                distributionDBExtendedCmd.CommandTimeout = _distributorSession.SqlQueryTimeoutInSeconds;
                using (var extendedInfoReader = distributionDBExtendedCmd.ExecuteReader())
                {
                    while (extendedInfoReader.Read())
                    {
                        string databaseName = (string)extendedInfoReader["name"];
                        DistributionDatabase database = distributionDatabases.Find(
                            d => d.Name.Equals(databaseName, StringComparison.InvariantCultureIgnoreCase)
                            );

                        if (database != null)
                        {
                            database.MinimumRetensionPeriod = (int)extendedInfoReader["min_distretention"];
                            database.MaximumRetensionPeriod = (int)extendedInfoReader["max_distretention"];
                            database.HistoryRetensionPeriod = (int)extendedInfoReader["history_retention"];
                            database.HistoryCleanupAgent = new SqlJob
                                                               {
                                                                   Name = (string)extendedInfoReader["history_cleanup_agent"]
                                                               };
                            database.DistributionCleanupAgent = new SqlJob
                                                                    {
                                                                        Name = (string)extendedInfoReader["distributor_cleanup_agent"]
                                                                    };

                            if (extendedInfoReader.FieldCount > 7)
                            {
                                database.DataFolder = (string)extendedInfoReader["data_folder"];
                                database.DataFile = (string)extendedInfoReader["data_file"];
                                database.DataFileSizeInMB = (int)extendedInfoReader["data_file_size"];
                                database.TransactionLogFolder = (string)extendedInfoReader["log_folder"];
                                database.TransactionLogFile = (string)extendedInfoReader["log_file"];
                                database.TransactionLogFileSizeInMB = (int)extendedInfoReader["log_file_size"];
                            }

                        }

                    }
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
                throw;
            }
        }

        private void GetDistributionDatabases(SqlConnection connection, List<DistributionDatabase> distributionDatabases)
        {
            try
            {
                SqlCommand getDistributionDatabaseCmd = new SqlCommand(ReplicationExplorerSqlQueries.SelectDistributionDatabases, connection);
                getDistributionDatabaseCmd.CommandTimeout = _distributorSession.SqlQueryTimeoutInSeconds;
                using (SqlDataReader reader = getDistributionDatabaseCmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        DistributionDatabase distributionDatabase = new DistributionDatabase();
                        distributionDatabase.DistributorSession = _distributorSession;
                        distributionDatabase.Name = (string)reader["DatabaseName"];
                        distributionDatabase.DatabaseState = (string)reader["DatabaseState"];
                        distributionDatabase.Collation = (string)reader["DatabaseCollation"];
                        distributionDatabase.RecoveryModel = (string)reader["RecoveryModel"];
                        distributionDatabase.IsSyncWithBackup = (bool)reader["IsSyncWithBackup"];
                        distributionDatabases.Add(distributionDatabase);
                    }
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
                throw;
            }
        }
    }
}